WimpSWIVe       0.07 (24 May 2001)
==================================


 NewerLook needs to trap Wimp_ SWIs in order to provide its new error
windows. The only official way to trap SWIs is to trap the SWI hardware
vector, but even this is not recommended. It takes much code to implement
properly in *all* circumstances (about 30K of source code in Desktop Hacker),
and can slow the machine down, quite considerably when there are multiple
claimants.

 It is, however, possible to trap Wimp_ SWIs by providing another module
with the same SWI chunk and names. This method is much quicker and easier,
but it is - as Ill happily admit - rather dodgy. One of the problems is
that only one module can do this at a time. So if NewerLook had a module
that used this method, it wouldnt work properly when another program tried
to do the same thing. (And you know some program will.)

 Thus, I have separated the trapping code from the action code (which resides
in another module), and released this module separately. It can manage SWI
claims and releases dynamically, a bit like vectors. Actually, quite a lot
like vectors. You can use it in your own programs if you like. Heres how.

 Because WimpSWIVe uses the Wimps SWI chunk, it cannot provide its own
SWIs. Instead, it communicates using a Wimp SWI, namely Wimp_RegisterFilter.
Here is the WimpSWIVe specification for Wimp_RegisterFilter.


            |                                             Wimp_RegisterFilter
            |                                                    (SWI &400F5)
            |
            | Used by the Filter Manager to register or deregister a filter
            | OR used to register SWI claims and releases with WimpSWIVe
            |
  On entry: | R0 = reason code:
            |         &49575357 (WSWI) for WimpSWIVe operation (see below)
            |         anything else for filter operation (see RISC OS 3
            |         Programmers Reference Manual, page 3-224)
            | R1 = SWI word:
            |         bits 0-5 : offset in SWI chunk of SWI to claim/release
            |         bit  6   : ignore bits 0-5 and claim all Wimp_ SWIs
            |         bit  7   : undefined, leave unset
            |         bit  8   : post-trap code doesn't update V  }
            |         bit  9   : post-trap code doesn't update C  } see
            |         bit 10   : post-trap code doesn't update Z  } footnote
            |         bit 11   : post-trap code doesn't update N  } 3
            |         bits12-29: undefined, leave unset
            |         bit  30  : high priority if set, else low priority
            |         bit  31  : claim if set, else release
            | R2 = value to be passed in R12 on entry to code
            | R3 = address of SWI pre-trapping code, or 0 if none needed
            | R4 = address of SWI post-trapping code, or 0 if none needed
            |
   On exit: | Registers preserved
            |
Interrupts: | Interrupts may be enabled
            | Fast interrupts may be enabled
            |
 Processor: | Processor is in SVC mode
            |
Reentrancy: | SWI is not re-entrant
            |
       Use: | In WimpSWIVe usage, this SWI is used to claim or release SWIs.
            | The pre-trapping code specified is called before the SWI is
            | called, and the post-trapping code afterwards.
            |
            | High-priority pre-code is called before low priority pre-code.
            | (And high-priority post-code is called after low priority
            | post-code.) This is important because one piece of pre-code
            | could intercept a SWI call before another bit got a look in.
            | You should use high-priority code for monitoring and register-
            | altering code. If your pre-code is at all likely to intercept
            | a SWI, you must use low-priority code. In effect, low-priority
            | code is closer to the real SWI.
            |
            | Pre-trapping code conditions:
            |
            | On entry: R0-R8   = registers passed to SWI
            |           R9      = offset into chunk of SWI called
            |           R12     = value specified when RegisterFilter called
            |           R13     = full, descending stack
            |           R14     = return address (with V flag clear on
            |                     26 bit systems)
            |           N,Z,C,V = undefined
            |           I       = set
            |           F       = undefined
            |           mode    = SVC_26 or SVC_32 depending on whether
            |                     we're running on a 26 bit or 32 bit OS
            |
            |  On exit: R0-R8   = may be altered to change effect of SWI
            |           R9      = preserved, or -1 to intercept SWI
            |           R10-R12 = may be corrupted
            |           R14     = may be corrupted
            |           N,Z,C,V = if R9=-1, these flags are returned to the
            |                     caller
            |                     otherwise, they are ignored and may be
            |                     corrupted
            |           I       = may be corrupted
            |           F       = preserved
            |           mode    = preserved
            |
            |
            | If R9=-1 on exit, the SWI is not called. Instead, any
            | outstanding post-code is called, and the caller is returned to
            | with the supplied R0-R8 and PSR flags. An error may be
            | signified by pointing R0 to an error block and setting the V
            | flag on return as normal, when intercepting. (See footnote 1.)
            |
            | Note that unless you set R9=-1, there is no need to preserve
            | the PSR flags. This may be of use when writing code that has
            | to be run on both 26 bit and 32 bit versions of RISC OS.
            |
            | If more than one client has claimed a SWI, it is the earliest
            | claimants pre-trapping code that is called last - new
            | claimants take priority (though high-priority always beats low-
            | priority, of course). If interception occurs, any post-trapping
            | code for claims where the pre-trapping code (if any) has
            | already been executed are also executed. In effect, you are
            | guaranteed that you will get a post-trap event if you have had
            | a pre-trap. (See footnote 2.)
            |
            |
            | Post-trapping code conditions:
            |
            | On entry: R0-R8   = registers passed back from SWI
            |           R9      = offset into chunk of SWI called
            |           R12     = value specified when RegisterFilter called
            |           R13     = full, descending stack
            |           R14     = return address (with flags returned from
            |                     SWI on 26 bit systems)
            |           N,Z,C,V = flags returned from SWI
            |           I       = set (i.e. interrupts disabled)
            |           F       = undefined
            |           mode    = SVC_26 or SVC_32 depending on whether
            |                     we're running on a 26 bit or 32 bit OS
            |
            |  On exit: R0-R8   = may be altered to change perceived results
            |           R9      = preserved
            |           R10-R12 = may be corrupted
            |           R14     = may be corrupted
            |           N,Z,C,V = may be altered to change reults passed
            |                     back to caller (see footnote 3).
            |           I       = may be corrupted
            |           F       = preserved
            |           mode    = preserved
            |
            | If more than one client has claimed a SWI, it is the earliest
            | claimants post-trapping code that is called first, subject
            | to priority. (See footnote 2.)
            |
            | Remember that your post-trapping code may well be entered in an
            | error condition. You can determine this by checking if the V
            | flag is set on entry - R0 will point to an error block if it
            | is. See footnote 3 for details about preserving flags on exit.
            |
            |
            |
            |
            | Unlike OS_Claim, this SWI will not remove previous instances of
            | claims with the same values. The release routine also only
            | removes one instance of the values at a time. When releasing,
            | you only need to make sure bits 0-6 of R1 agree with the values
            | you gave when claiming - the other flags are ignored.
            |
            | Claiming the Wimp_RegisterFilter SWI only traps the normal
            | filter-based use of the SWI. Under no circumstances should you
            | call Wimp_RegisterFilter with WimpSWIVe usage in your trapping
            | code. If you really must claim or release a SWI when some other
            | SWI is executed, use a CallBack to do it. (See the RISC OS 3
            | Programmers Reference Manual, page 1-319.)
            |
            | Dont post-trap Wimp_Poll(Idle) or Wimp_StartTask: its a bad
            | idea. WimpSWIVe deals with it adequately, but there are all
            | sorts of simply horrid implications. Trapping Wimp_Poll is
            | easy anyway, using the old filter system.
            |
            | And finally, dont use the claim all SWIs flag unless you
            | really want all the SWIs. Dont use it for trapping a number
            | of different SWIs, use many separate claims: the speed
            | difference will be negligable, and you neednt worry about
            | Wimp_Poll. The claim all SWIs flag is unlikely to be widely
            | useful - a Wimp SWI logging program seems to be the only
            | possible user.
            |
    Errors: | Bad value passed to WIMP in R0
            |    if WimpSWIVe is not loaded, the attempt to use this SWI in
            |    the WimpSWIVe manner will cause this error
            | Bad WimpSWIVe release
            |    releasing a SWI you had not claimed generates this error
            | No room in RMA
            |    is also possible but highly unlikely.
            |


 Footnote 1 - Re-entrancy issues:

 Re-entrancy is nae problem if you only use pre-trapping or only use post-
trapping - you can either be re-entrant by using a stack to store stuff, or
prevent re-entering using a threaded flag (and unless you call a SWI, you
cannot be re-entered anyway). If you use both, but the post-code always does
the same regardless of the pre-code, youre all right too.

 But if you use both at once and the action of post depends on something
that happened in pre (for example if you have pre to check the reason code
is worth bothering with in the post-trap code), it is slightly more complex.
Its quite possible that calling a Wimp SWI may cause another Wimp SWI to be
called, especially when you consider there can be many WimpSWIVe claimants.
Consider:

     SWI Wimp_Thing called
       WimpSWIVe claimant 1 pre-traps SWI
         Claimant 1 store data for SWI 1 in workspace
       WimpSWIVe claimant 2 pre-traps SWI
         Claimant 2 executes Wimp_Gubbins
           Wimp_Gubbins causes Wimp_Thing to be called
             WimpSWIVe claimant 1 pre-traps SWI
               Claimant 1 stores data for SWI 2 in workspace
             WimpSWIVe claimant 2 pre-traps SWI
               Claimant 2 is threaded, and so does nothing
             WimpSWIVe executes real SWI Wimp_Thing
             WimpSWIVe claimant 2 post-traps SWI
               Claimant 2 is threaded, and so does nothing
             WimpSWIVe claimant 1 post-traps SWI
               Claimant 1 performs action on results, dependent on workspace
               which holds data for SWI 2
             WimpSWIVe returns
       WimpSWIVe executes real Wimp_Thing SWI
       WimpSWIVe claimant 2 post-traps SWI
         Claimant 2 does whatever it needs to with results
       WimpSWIVe claimant 1 post-traps SWI
         Claimant 1 performs action on results, dependent on workspace
         which holds data for SWI *2*
       WimpSWIVe returns

 As you can see, there is a lot of scope here for things going wrong, and
horrible clashes where one WimpSWIVe program may make another go wrong,
potentially rather messily.

 There are two things you can do about it. Perhaps the best is to store a
count of post-traps to ignore. This count should be zero initially, and
should be incremented first when your pre-trap code detects that post-
trapping should do something effective. It should also be incremented every
time the pre-trap code is entered with the count non-zero. The post trap code
then checks the count on entry. If the count is zero, it returns doing
nothing. If the count is one or greater, the count is decremented. If the
count is one exactly one, the effect of the post-trap is activated. Theres
an example of this in the EigenSysInfo source.

 This is fine normally, but it makes the trapping code only affect the first
SWI to be affected (the "outermost" affected SWI). If you want to be truly
re-entrant, youd have to store values on the stack to indicate whether to
post-trap on each call. And you couldnt use the SVC stack, so youd have to
use a private stack. And youd have to revert to the above behaviour if the
stack was filled up. Therefore, I dont reckon its worth bothering with,
especially as allowing true re-entrancy opens the door to recursive problems
(Wimp_Thing calls Wimp_Gubbins calls Wimp_Thing calls Wimp_Gubbins etc.) too.

 Sorry about the complexity of this footnote. Relax. You dont need to
bother about all this horrid stuff, usually. :-)


 Footnote 2:

 Your post-trap code will only be called if the SWI does return. This might
not happen if the SWI is one that doesnt return (but I cant think of any
Wimp_ SWIs that dont), or if a serious error happens. The latter should
never happen in a perfect system, but bugs happen and the SWI being trapped
might branch through zero or something. With the Wimp, though, a crash at
this stage often means there is something very wrong with the whole desktop
and everything is going to die anyway, so your module failing to post-trap
is unlikely to annoy the user much. :-)


 Footnote 3:
 
 In order to ease 26/32bit compatability, some changes have been made to
how flags are handled on exit from post-trap routines:

 The processor NZCV flags when you exit from your post-trap routine can
optionally be passed back to the caller of the SWI, or ignored, independently
of each other. To pass a flag back to the caller, you must *clear* the
appropriate bit in R1 when registering your filter with WimpSWIVe. Setting
the bit means that the corresponding flag will be ignored. Whether you set
or clear the appropriate bit may seem to be the wrong way round logically,
but it is done this way to maintain compatability with code that is expecting
older versions of WimpSWIVe, where flags were always passed back to the
caller after a post-trap routine.
 Note also that these flags are in bits 8-11 of R1, leaving bit 7 unused.

 There now follows some examples of how to manipulate flags in a way that is
compatible with 26 bit and 32 bit versions of RISC OS.

 If you don't want to alter any of the flags the SWI normally returns, you
just need to set all four appropriate flag bits in R1 when registering your
filter, and then exit your post-trap routine with MOV PC,R14.

 If you want to modify all the flags on return, you should clear all four
flag bits in R1 when registering your filter, and then exit with the
following instructions, assuming that the appropriate NZCV flags are in bits
31-28 of R10:
                    AND    R10,R10,#&F0000000
                    TEQ    PC,PC
                    BICNE  R14,R14,#&F0000000
                    ORRNE  R14,R14,R10
                    MOVNES PC,R14
                    MSR    R11,CPSR
                    BIC    R11,R11,#&F0000000
                    ORR    R11,R11,R10
                    MRS    CPSR_F,R11
                    MOV    PC,R14
Remember that you're in SVC mode, so TEQ PC,PC will set Z according to
whether it's SVC_26 or SVC_32. Also remember that you can quite happily
corrupt R10 and R11 (as well as R12 and R14) on exit.

 If you only want to update some flags on return, the above code will also
work, providing you set the appropriate mask in R1 when registering the
filter with WimpSWIVe. If there is only one flag to update, you might find
it easier to use a processor independent instruction sequence to set the
flag, rather than the code above. For example:
      to clear V and exit:  MOV R10,#0
                            CMN R10,#&80000000
                            MOV PC,R14
                   
      to set V and exit:    MOV R10,#0
                            CMP R10,#&80000000
                            MOV PC,R14
                   
      to set Z and exit:    CMP R10,R10
                            MOV PC,R14
      
      etc.
Remember to set the appropriate mask when registering a filter with WimpSWIVe
before doing this to make sure that you don't accidentally return any flags
you didn't mean to.

 If you want to do different things in your post-trap depending on the flags
returned by the SWI, remember that the flags on entry to your code are those
that the SWI (or an earlier post-trap) has returned, so a simple BVC or BVS
(for example) to appropriate code might be enough. However, to get the flags
into a register, the following code will work:
                   MOV R10,PC
                   MRS R10,CPSR
                   AND R10,R10,#&F0000000
This puts NZCV into the top four bits of R10, with the rest of R10 clear. You
might not need the final AND instruction, depending on your own
circumstances. Remember that MRS (and also MSR) is a no-op 26-bit only
versions of the ARM.

 Finally, remember that the above applies to post-trapping code ONLY. The
flags on entry and exit to pre-trapping code are irrelevant and ignored,
unless your pre-trap exits with R9=-1, in which case the current flags are
always returned to the SWI caller, including V to flag an error. You might
find the above examples on how to set or clear V independently of the
processor useful in this situation. Also note that, in pre-trapping code
ONLY, the following sequence will return with V clear on 26-bit versions
of RISC OS:
                   TEQ PC,PC
                   MOVNES R15,R14
This may or may not be useful...


-----------------------------------------------------------------------------

 This module is supplied with two example programs:
 
 - Pointer. This is a somewhat contrived example of how to manipulate flags
   in post-trapping code. If a call to get Wimp_GetPointerInfo returns an
   error (e.g. Bad pointer in R1), then OS_Mouse will be called to find out
   the current button state. If no buttons are pressed, Z will be set,
   otherwise it will be cleared. This is done in a 26/32bit compatible way,
   whilst preserving V (and the other flags). If the call to
   Wimp_GetPointerInfo didn't return an error, the flags are left unaltered.
   This is a good example of some of the ideas described in footnote 3.

 - EigenSysInfo. This is a pretty useless one that changes Wimp_ReadSysInfo
   2 always to return 24 or 22, and return the latter if Log2YEig<2 (the
   WIMP returns 22 if Log2YEig==Log2XEig, which is silly). It also goes
   beep if the Wimp returned a different value to it (try mode 22 and the
   like). Its not particularly great because most programs dont take any
   notice of ReadSysInfo (partly because of its aforementioned bobbinsness)
   but it shows you how to pre-trap and post-trap SWIs at the same time (as
   in footnote 1).

 These programs, along with their sources, can be found in the Examples
directory. The full source for WimpSWIVe requires RISC OS 4
(or something that provides MSR and MRS instructions in the same format as
the RO4 assembler) to compile.

 If you use this module in a program, be sure to RMEnsure version 0.07 or
later - the ealier versions are not compatible with a 32-bit versions of RISC
OS, or contain bugs. You might also find the 'Load' program in the Utils
directory useful - this is a nasty hack that reads all the details from
WimpSWIVe's workspace, deregisters all the filters, loads a new copy, and
then re-registers all the filters. This can be used to prevent the 'WimpSWIVe
cannot be quit right now...' errors that will occur if somebody has already
loaded an earlier version of WimpSWIVe before you.


Version history (from 0.05):

0.05 (30 Oct 1995): Last version released by Andrew Clover.

0.06 (14 May 2001): First release by Andrew Booker.
                    Made 32 bit compatible.
                    Added the feature of possibly not returning flags from
                    post-trap code.

0.07 (24 May 2001): Fixed a small bug in the Load utility.
                    




 This module is freeware, and up to version 0.05 was written by Andrew
Clover. Later versions have been modified by Andrew Booker, although still
maintain much of Andrew Clover's code. Feel free to distribute and use.

 Contact details:
For praise, to suggest new bits to add, or (heaven forbid) to report a bug,
please write to:

  Andrew Clover,                  Andrew Booker,
  Griesbadgasse 20,               155 Sandygate Road,
  D-85049 Ingostadt,              Crosspool,
  Germany.                        Sheffield,
                                  S10 5SA.
      
  E-mail: andrew@oaktree.co.uk    E-mail: ajb121@york.ac.uk (until June 2001)

The latest version of this module will be avaiable, until the end of June
2001, from http://www-users.york.ac.uk/~ajb121

Andrew Clover's last release, 0.05, is available from
http://www.doggsoft.co.uk
